package common;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import com.mysql.opt.Operator;

public class FileCompressTool {
	
	private final static int FILE_BUFFER_SIZE = 20480;
	
	public static void ZipFiles(String[] filePath, String location, String comment, String encoding){
		try {
			Long beginTime = new Date().getTime();
			FileOutputStream fos = new FileOutputStream(location);
			CheckedOutputStream checkOut=new CheckedOutputStream(fos,new CRC32());
			ZipOutputStream zipOut=new ZipOutputStream(new BufferedOutputStream(checkOut));  
			System.out.println("Set Comment: " + comment);
			zipOut.setComment(comment);
			Map<String, String> map = FileCompressTool.getFileNameMap(filePath);
			Set<String> keySet = map.keySet();
			Long totalFileSz = 0L;
			for(Iterator<String> iter = keySet.iterator();iter.hasNext();){
				String key = iter.next();
				String fileName = map.get(key);
							
				File fi = new File(fileName);
				totalFileSz += fi.length();
				System.out.println("Compressing: " + fileName + " Size:"+fi.length());
				BufferedReader in=new BufferedReader(new InputStreamReader(new FileInputStream(fi),encoding)); 
	            zipOut.putNextEntry(new ZipEntry(key));//建立压缩实体  
	            String line;
	            //当压缩过程未结束时继续读写  
	            while((line=in.readLine())!=null){
	            	line.replaceAll(Operator.nextline, "JDBC-N-LINE");
	                zipOut.write(line.getBytes());                
	            } 
	            in.close();  
			}
            zipOut.close();  
            Long endTime = new Date().getTime();
            File tarFile = new File(location);
            Long aftZipSz = tarFile.length();
            Double rate = (1 - aftZipSz.doubleValue()/totalFileSz.doubleValue())*100;
            System.out.println("Finish!\nTime Cost:" + (endTime - beginTime) + "ms\nCompressRate: " + NumberProcess.floatNum(rate, 2) + "%");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}  
	}
	
	public static boolean UnZipFile(String zipFilePath, String targetFileDir){
		File compressedZip = new File(zipFilePath);
		Long beginTime = new Date().getTime();
		boolean flag = false;
		try {			
			ZipFile zipFile = new ZipFile(compressedZip);
			zipFile.close();
			File tarDir = new File(targetFileDir);
			if(tarDir.isDirectory()){
				if(!tarDir.exists()){
					System.out.println("Generating Dir: " + tarDir.getAbsolutePath());
					tarDir.mkdirs();
				}				
			}else{
				System.out.println("Generating Dir: " + tarDir.getAbsolutePath());
				tarDir.mkdirs();
			}
			ZipInputStream zis = new ZipInputStream(new FileInputStream(compressedZip));
			ZipEntry zen;
			while((zen = zis.getNextEntry())!=null){
				System.out.println("Decompressing: " + zen.getName());
				if(zen.isDirectory()){
					File dirInZip = new File(tarDir.getAbsolutePath() + File.separator + zen.getName());
					System.out.println("Generating Dir: " + dirInZip.getAbsolutePath());
					dirInZip.mkdirs();
				}else{
					File fiInZip = new File(tarDir.getAbsolutePath() + File.separator + zen.getName());
					if(!fiInZip.getParentFile().exists()){
						System.out.println("Generating Dir: " + fiInZip.getParentFile().getAbsolutePath());
						fiInZip.getParentFile().mkdirs();
					}
					FileOutputStream fos = new FileOutputStream(fiInZip);
					int byteVal;
					int cursor = 0;
					byte[] bArray = new byte[FILE_BUFFER_SIZE];
					while((byteVal = zis.read())!=-1){
						bArray[cursor] = (byte) byteVal;
						cursor++;
						if(cursor == FILE_BUFFER_SIZE){
							cursor = 0;
							fos.write(bArray);
						}
					}
					if(cursor!=0){
						fos.write(bArray, 0, cursor);
					}
					fos.flush();
					fos.close();
				}
			}
			flag = true;
		} catch (ZipException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Long endTime = new Date().getTime();        
		System.out.println((flag)?"Finish!":"Failed");
        System.out.println("Time Cost:" + (endTime - beginTime) + "ms");	
		return flag;
	}
	
	private static Map<String, String> getFileNameMap(String[] filePath){
		 Map<String, String> map = new HashMap<String, String>();
		 FileControlSet fcs = new FileControlSet();
		 for(int i=0;i<filePath.length;i++){
			 File fi = new File(filePath[i]);
			 if(fi.isDirectory()){
				 String dirParent = fi.getParent();
				 List<File> fileList = fcs.Find_NoFilter(fi.getAbsolutePath());
				 for(int j=0;j<fileList.size();j++){
					 File fIn = fileList.get(j);
					 String key = fIn.getAbsolutePath().replace(dirParent, "");
					 map.put(key, fIn.getAbsolutePath());
				 }
			 }else{
				 map.put(fi.getName(), fi.getAbsolutePath());
			 }
		 }
		 return map;
	 }
}
